﻿using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Application = Autodesk.AutoCAD.ApplicationServices.Core.Application;

namespace AutoCAD_CSharp_plug_in3.Chap02
{
    public static class Ig541Action
    {
        /// <summary>
        /// 获取集流管的起点和终点位置
        /// </summary>
        /// <param name="startPoint">图形起点</param>
        /// <param name="xinghao">钢瓶型号:1=80L, 2=90L</param>
        /// <param name="dsp">单双排:1=单排, 2=双排</param>
        /// <param name="fangxiang">方向:1=横向, 2=竖向</param>
        /// <param name="shuliang">钢瓶数量</param>
        /// <returns>集流管的起点和终点</returns>
        private static (Point3d startPoint, Point3d endPoint) GetJiLiuGuanPosition(Point3d startPoint,
            int xinghao, int dsp, int fangxiang, int shuliang)
        {
            if (xinghao == 1) // 80L
            {
                if (dsp == 1) // 单排
                {
                    if (fangxiang == 1) // 横向
                    {
                        var s = startPoint.CP(0, -150);
                        var e = new Point3d(startPoint.X + (150 + (320 * shuliang)), startPoint.Y - 150, 0);
                        return (s, e);
                    }
                    else // 竖向
                    {
                        var s = startPoint.CP(250, 0);
                        var e = new Point3d(startPoint.X + 250, startPoint.Y - (150 + (320 * shuliang)), 0);
                        return (s, e);
                    }
                }
                else // 双排
                {
                    int num = shuliang / 2;
                    int num1 = shuliang % 2;
                    if (num1 > 0) num++;

                    if (fangxiang == 1) // 横向
                    {
                        var s = startPoint.CP(0, -325);
                        var e = new Point3d(startPoint.X + (150 + (320 * num)), startPoint.Y - 325, 0);
                        return (s, e);
                    }
                    else // 竖向
                    {
                        var s = startPoint.CP(325, 0);
                        var e = new Point3d(startPoint.X + 325, startPoint.Y - (150 + (320 * num)), 0);
                        return (s, e);
                    }
                }
            }
            else // 90L
            {
                if (dsp == 1) // 单排
                {
                    if (fangxiang == 1) // 横向
                    {
                        var s = startPoint.CP(0, -150);
                        var e = new Point3d(startPoint.X + (150 + (360 * shuliang)), startPoint.Y - 150, 0);
                        return (s, e);
                    }
                    else // 竖向
                    {
                        var s = startPoint.CP(250, 0);
                        var e = new Point3d(startPoint.X + 250, startPoint.Y - (150 + (360 * shuliang)), 0);
                        return (s, e);
                    }
                }
                else // 双排
                {
                    int num = shuliang / 2;
                    int num1 = shuliang % 2;
                    if (num1 > 0) num++;

                    if (fangxiang == 1) // 横向
                    {
                        var s = startPoint.CP(0, -375);
                        var e = new Point3d(startPoint.X + (150 + (360 * num)), startPoint.Y - 375, 0);
                        return (s, e);
                    }
                    else // 竖向
                    {
                        var s = startPoint.CP(375, 0);
                        var e = new Point3d(startPoint.X + 375, startPoint.Y - (150 + (360 * num)), 0);
                        return (s, e);
                    }
                }
            }
        }

        public static void Ig541Test()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            do
            {
                int gangpingXinghao = 0; //钢瓶型号
                int fangxiang = 0; //方向
                int dsp = 0; //单双排
                int shuliang = 0; //钢瓶数量


                //钢瓶型号
                PromptIntegerResult pir = ed.GetInteger("请选则钢瓶型号（1:80L    2:90L）:");
                if (pir.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("填写有误");
                    return;
                }

                gangpingXinghao = pir.Value;

                //单双排
                PromptIntegerResult pir0 = ed.GetInteger("请单双排（1:单排    2:双排）:");
                if (pir0.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("填写有误");
                    return;
                }

                dsp = pir0.Value;

                //方向
                PromptIntegerResult pir1 = ed.GetInteger("请输入布置方向（1:横向    2:竖向）:");
                if (pir1.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("填写有误");
                    return;
                }

                fangxiang = pir1.Value;

                //钢瓶数量
                string msg = dsp == 1 ? "(1-5)" : "(1-10)";

                PromptIntegerResult pir2 = ed.GetInteger("请输入钢瓶数量" + msg + ":");
                if (pir2.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("填写有误");
                    return;
                }

                shuliang = pir2.Value;

                PromptPointResult pr = ed.GetPoint("请选择一个插入点:\n");
                if (pr.Status != PromptStatus.OK)
                {
                    return;
                }

                Point3d point = pr.Value;
                ObjectId spaceId = db.CurrentSpaceId;
                NewMethod(db, gangpingXinghao, dsp, fangxiang, point, shuliang,out var ens);
            } while (true);
        }

        public static void NewMethod(Database db, int gangpingXinghao, int dsp, int fangxiang, Point3d point, int shuliang,out List<Entity> ens)
        {
             ens = new List<Entity>();
            
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                try
                {
                    DocumentLock docLock = Application.DocumentManager
                        .MdiActiveDocument.LockDocument();
                    //打开表
                    BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                    //打开表记录
                    BlockTableRecord btr =
                        (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                
                    if (gangpingXinghao == 1)
                    {
                        if (dsp == 1)
                        {
                            if (fangxiang == 1)
                            {
                                ens = IG54180LA1.HorizontalDP(point, shuliang); // 80  横向 单排
                            }
                            else
                            {
                                ens = IG54180LA1.VerticalDP(point, shuliang); // 80  竖向 单排
                            }
                        }
                        else
                        {
                            if (fangxiang == 1)
                            {
                                ens = IG54180LA1.HorizontalSP(point, shuliang); // 80  横向 双排
                            }
                            else
                            {
                                ens = IG54180LA1.VerticalSP(point, shuliang); // 80  竖向 双排
                            }
                        }
                    }
                    else
                    {
                        if (dsp == 1)
                        {
                            if (fangxiang == 1)
                            {
                                ens = IG54190LA1.HorizontalDP(point, shuliang); // 90L 横向  单排
                            }
                            else
                            {
                                ens = IG54190LA1.VerticalDP(point, shuliang); //90L 竖向  单排
                            }
                        }
                        else
                        {
                            if (fangxiang == 1)
                            {
                                ens = IG54190LA1.HorizontalSP(point, shuliang); //90L 横向  双排
                            }
                            else
                            {
                                ens = IG54190LA1.VerticalSP(point, shuliang); // 90L 竖向 双排
                            }
                        }
                    }


                    foreach (var item in ens)
                    {
                        btr.AppendEntity(item);
                        trans.AddNewlyCreatedDBObject(item, true);
                    }

                    trans.Commit();
                    docLock.Dispose();
                }
                catch (Exception e)
                {
                    trans.Abort();
                }
            }
        }

        /// <summary>
        /// IG541钢瓶瓶组平移命令 - 将集流管与选择线上任意点为基点，保持平行方向相同
        /// </summary>
        public static void Ig541Rel()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

            //  选择参考点
            if (GetValue0(ed, db, out var selectedPoint, out var lineAngle)) return;

            // 获取瓶组参数
            if (GetValue(ed, out var xinghao, out var dsp, out var fangxiang, out var shuliang)) return;

            // 默认集流管角度，横向=0度，竖向=90度
            double defaultAngle = (fangxiang == 1) ? 0 : Math.PI / 2;

            // 计算旋转的角度，如果未选择线上点，则不旋转
            double rotationAngle = (lineAngle ?? defaultAngle) - defaultAngle;

            // 生成图形
            var ens = GenEntity(xinghao, dsp, fangxiang, shuliang);

            // 找到集流管并计算起点
            Point3d jlgStartPoint = Point3d.Origin;
            foreach (Entity entity in ens)
            {
                if (!(entity is Line line) || !IsJiLiuGuan(line, xinghao, dsp, fangxiang, shuliang)) continue;
                jlgStartPoint = line.StartPoint;
                break;
            }

            // 先旋转再平移
            Matrix3d rotation = Matrix3d.Rotation(rotationAngle, Vector3d.ZAxis, Point3d.Origin);
            Matrix3d translation = Matrix3d.Displacement(selectedPoint - jlgStartPoint.TransformBy(rotation));
            Matrix3d combined = rotation.PreMultiplyBy(translation);

            // 绘制变换后的图形
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr =
                    (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

                using (Application.DocumentManager.MdiActiveDocument.LockDocument())
                {
                    foreach (var item in ens)
                    {
                        item.TransformBy(combined);
                        btr.AppendEntity(item);
                        trans.AddNewlyCreatedDBObject(item, true);
                    }
                }

                trans.Commit();
            }
        }

        public static List<Entity> GenEntity(int xinghao, int dsp, int fangxiang, int shuliang)
        {
            Point3d tempStartPoint = Point3d.Origin;
            List<Entity> ens;
            if (xinghao == 1)
            {
                if (dsp == 1)
                {
                    if (fangxiang == 1)
                    {
                        ens = IG54180LA1.HorizontalDP(tempStartPoint, shuliang);
                    }
                    else
                    {
                        ens = IG54180LA1.VerticalDP(tempStartPoint, shuliang);
                    }
                }
                else
                {
                    if (fangxiang == 1)
                    {
                        ens = IG54180LA1.HorizontalSP(tempStartPoint, shuliang);
                    }
                    else
                    {
                        ens = IG54180LA1.VerticalSP(tempStartPoint, shuliang);
                    }
                }
            }
            else
            {
                if (dsp == 1)
                {
                    if (fangxiang == 1)
                    {
                        ens = IG54190LA1.HorizontalDP(tempStartPoint, shuliang);
                    }
                    else
                    {
                        ens = IG54190LA1.VerticalDP(tempStartPoint, shuliang);
                    }
                }
                else
                {
                    if (fangxiang == 1)
                    {
                        ens = IG54190LA1.HorizontalSP(tempStartPoint, shuliang);
                    }
                    else
                    {
                        ens = IG54190LA1.VerticalSP(tempStartPoint, shuliang);
                    }
                }
            }

            return ens;
        }

        private static bool GetValue0(Editor ed, Database db, out Point3d selectedPoint, out double? lineAngle)
        {
            selectedPoint = Point3d.Origin;

            PromptEntityOptions entOpt = new PromptEntityOptions("\n请选择线上的参考点,回车选择任意参考点:");
            entOpt.SetRejectMessage("\n请选择线上的参考点,回车选择任意参考点:");
            entOpt.AddAllowedClass(typeof(Curve), false);
            entOpt.AllowNone = true;

            lineAngle = null;
            PromptEntityResult entRes = ed.GetEntity(entOpt);
            if (entRes.Status == PromptStatus.OK)
            {
                // 请选择线上的参考点
                PromptPointResult pointRes = ed.GetPoint("\n请选择线上的参考点:");
                if (pointRes.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("操作已取消");
                    return true;
                }

                selectedPoint = pointRes.Value;

                // 计算对象方向角，并将点投影到对象上
                using (Transaction trs = db.TransactionManager.StartTransaction())
                {
                    Entity ent = (Entity)trs.GetObject(entRes.ObjectId, OpenMode.ForRead);
                    if (ent is Curve curve)
                    {
                        // 投影点到曲线，获取切线方向
                        Point3d onCurve = curve.GetClosestPointTo(selectedPoint, false);
                        Vector3d direction;
                        if (ent is Line line)
                        {
                            direction = line.EndPoint - line.StartPoint;
                        }
                        else
                        {
                            direction = curve.GetFirstDerivative(onCurve);
                        }

                        lineAngle = Math.Atan2(direction.Y, direction.X);
                        selectedPoint = onCurve; // 使用曲线上的最近点
                    }

                    trs.Commit();
                }
            }
            else if (entRes.Status == PromptStatus.None)
            {
                // 未选择对象，直接选择参考点
                PromptPointResult pointRes = ed.GetPoint("\n请选择任意参考点:");
                if (pointRes.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("操作已取消");
                    return true;
                }

                selectedPoint = pointRes.Value;
            }
            else
            {
                ed.WriteMessage("操作已取消");
                return true;
            }

            return false;
        }

        private static bool GetValue(Editor ed, out int xinghao, out int dsp, out int fangxiang, out int shuliang)
        {
            (xinghao, dsp, fangxiang, shuliang) = (0, 0, 0, 0);

            const int min = 1;
            var max = 2;
            // 钢瓶型号
            PromptIntegerResult pir = ed.GetInteger(PromptIntegerOptions("\n请选择钢瓶型号(1:80L 2:90L):", min, max));
            if (pir.Status == PromptStatus.OK)
            {
                xinghao = pir.Value;
            }
            else
            {
                return true;
            }

            // 单双排
            PromptIntegerResult pir0 = ed.GetInteger(PromptIntegerOptions("\n请选择单双排(1:单排 2:双排):", min, max));

            if (pir0.Status == PromptStatus.OK)
            {
                dsp = pir0.Value;
            }
            else
            {
                return true;
            }

            // 方向
            PromptIntegerResult pir1 = ed.GetInteger(PromptIntegerOptions("\n请选择布置方向(1:横向 2:竖向):", min, max));
            if (pir1.Status == PromptStatus.OK)
            {
                fangxiang = pir1.Value;
            }
            else
            {
                return true;
            }

            // 钢瓶数量
            var msg = dsp == 1 ? "(1-5)" : "(1-10)";
            max = dsp == 1 ? 5 : 10;
            PromptIntegerResult pir2 = ed.GetInteger(PromptIntegerOptions("\n请选择钢瓶数量" + msg + ":", min, max));
            if (pir2.Status == PromptStatus.OK)
            {
                shuliang = pir2.Value;
            }
            else
            {
                return true;
            }

            return false;
        }


        private static PromptIntegerOptions PromptIntegerOptions(string msg, int min, int max)
        {
            var pio = new PromptIntegerOptions(msg)
            {
                AllowZero = false, // 不允许0
                AllowNegative = false, // 不允许负数
                AllowNone = false, // 不允许空输入
                DefaultValue = min, // 默认值设为1
                UseDefaultValue = true, // 使用默认值
                // 设置允许的值范围
                LowerLimit = min,
                UpperLimit = max
            };
            return pio;
        }


        /// <summary>
        /// 判断是否为集流管线
        /// </summary>
        public static bool IsJiLiuGuan(Line line, int xinghao, int dsp, int fangxiang, int shuliang)
        {
            var (s, e) = GetJiLiuGuanPosition(Point3d.Origin, xinghao, dsp, fangxiang, shuliang);

            // 在最小误差范围内
            const double tolerance = 1e-6;
            return (line.StartPoint.DistanceTo(s) < tolerance && line.EndPoint.DistanceTo(e) < tolerance) ||
                   (line.StartPoint.DistanceTo(e) < tolerance && line.EndPoint.DistanceTo(s) < tolerance);
        }
    }
}